// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package types2

import (
	"cmd/compile/internal/syntax"
	"fmt"
	"go/constant"
)

func (err *error_) recordAltDecl(obj Object) {
	if pos := obj.Pos(); pos.IsKnown() {
		// 我们在这里使用“other”而不是“previous”，因为
		// 看到的第一个声明可能不是源代码前面的文本
		// 。
		err.errorf(pos, "other declaration of %s", obj.Name())
	}
}

func (check *Checker) declare(scope *Scope, id *syntax.Name, obj Object, pos syntax.Pos) {
	// spec:“用下划线
	// 字符表示的空白标识符可以像任何其他
	// 标识符一样在声明中使用，但该声明不引入新的
	// 绑定。”
	if obj.Name() != "_" {
		if alt := scope.Insert(obj); alt != nil {
			var err error_
			err.errorf(obj, "%s redeclared in this block", obj.Name())
			err.recordAltDecl(alt)
			check.report(&err)
			return
		}
		obj.setScopePos(pos)
	}
	if id != nil {
		check.recordDef(id, obj)
	}
}

// pathString返回格式为a->b->…->g表示路径[a，b，…g]。
func pathString(path []Object) string {
	var s string
	for i, p := range path {
		if i > 0 {
			s += "->"
		}
		s += p.Name()
	}
	return s
}

// objDecl类型在其各自的（文件）环境中检查obj的声明。
// 有关def的含义，请参阅Checker。定义类型，在typexpr中。去
func (check *Checker) objDecl(obj Object, def *Named) {
	if check.conf.Trace && obj.Type() == nil {
		if check.indent == 0 {
			fmt.Println() // 为了可读性，顶级对象之间的空行
		}
		check.trace(obj.Pos(), "-- checking %s (%s, objPath = %s)", obj, obj.color(), pathString(check.objPath))
		check.indent++
		defer func() {
			check.indent--
			check.trace(obj.Pos(), "=> %s (%s)", obj, obj.color())
		}()
	}

	// 检查obj的声明意味着推断其类型
	// （可能还有常量的值）。
	// 一个对象的类型（因此该对象）可能处于
	// 三种用颜色表示的状态之一：
	// 
	// -类型未知的对象被涂成白色（初始颜色）
	// -正在推断类型的对象被涂成灰色
	// -类型未知的对象完全推断被涂成黑色
	// 
	// 在类型推断过程中，对象的颜色从白色变为灰色
	// 变为黑色（预先声明的对象从一开始就被涂成黑色）。
	// 黑色对象（即其类型）只能依赖（参考）其他黑色
	// 对象。白色和灰色对象可能依赖于白色和黑色对象。
	// 对灰色对象的依赖性表示一个周期可能有效，也可能无效。
	// 
	// 当对象变成灰色时，它们会被推到对象路径（堆栈）上；
	// 当它们变黑时会再次弹出。因此，如果遇到灰色对象（一个
	// 循环），它位于对象路径上，它所依赖的所有对象
	// 都是该路径上的剩余对象。颜色编码
	// 是指灰色对象的颜色值指示
	// 该对象在对象路径中的索引。

	// 在类型检查过程中，可以为白色对象分配一个类型，而不需要
	// 遍历objDecl；e、 例如，初始化常量和
	// 变量时。在这里更新这些对象的颜色（而不是
	// 我们设置类型的任何地方），以满足颜色不变量。
	if obj.color() == white && obj.Type() != nil {
		obj.setColor(black)
		return
	}

	switch obj.color() {
	case white:
		assert(obj.Type() == nil)
		// 除白色和黑色以外的所有颜色值均视为灰色。
		// 因为黑白是<灰色的，所以所有>=灰色的值都是灰色的。
		// 使用这些值将对象的索引编码到对象路径中。
		obj.setColor(grey + color(check.push(obj)))
		defer func() {
			check.pop().setColor(black)
		}()

	case black:
		assert(obj.Type() != nil)
		return

	default:
		// 白色或黑色以外的颜色值被视为灰色。我们有一个循环（可能无效）。
		fallthrough

	case grey:
		// 在现有代码中，对于对象，这是由非零类型
		// 标记的，但其
		// 类型可能为非零（已知）的常量和变量除外，或者如果依赖于
		// 尚未已知的初始化值，则为零。
		// 在前一种情况下，将类型设置为Typ[Invalid]，因为
		// 我们有一个初始化周期。确定初始化顺序时，循环错误将被
		// 稍后报告。
		// TODO（gri）报告循环并简化初始化
		// 订单代码。
		switch obj := obj.(type) {
		case *Const:
			if !check.validCycle(obj) || obj.typ == nil {
				obj.typ = Typ[Invalid]
			}

		case *Var:
			if !check.validCycle(obj) || obj.typ == nil {
				obj.typ = Typ[Invalid]
			}

		case *TypeName:
			if !check.validCycle(obj) {
				// 中断循环
				// （如果没有这个，下面调用底层（）
				// 可能会导致一个无休止的循环
				// 如果我们有一个定义的
				// /（*命名）类型）
				obj.typ = Typ[Invalid]
			}

		case *Func:
			if !check.validCycle(obj) {
				// 不要设置obj。这里的typ to typ[Invalid]
				// 因为很多代码类型断言
				// 函数具有*签名类型。灰色
				// 函数的类型设置为空
				// 签名，这使
				// 无法使用函数初始化变量。
			}

		default:
			unreachable()
		}
		assert(obj.Type() != nil)
		return
	}

	d := check.objMap[obj]
	if d == nil {
		check.dump("%v: %s should have been declared", obj.Pos(), obj)
		unreachable()
	}

	// 保存/恢复当前环境和设置对象环境
	defer func(env environment) {
		check.environment = env
	}(check.environment)
	check.environment = environment{
		scope: d.file,
	}

	// Const和var声明不能有初始化
	// 循环。我们通过记住当前的声明
	// 来跟踪它们。十二月。初始化表达式依赖于其他
	// 常量、变量或函数，将依赖项添加到当前
	// 检查。十二月。
	switch obj := obj.(type) {
	case *Const:
		check.decl = d // 新包级别const decl 
		check.constDecl(obj, d.vtyp, d.init, d.inherited)
	case *Var:
		check.decl = d // 新包级别var decl 
		check.varDecl(obj, d.lhs, d.vtyp, d.init)
	case *TypeName:
		// 通过路径检测到无效的递归类型
		check.typeDecl(obj, d.tdecl, def)
		check.collectMethods(obj) // 方法只能添加到顶级类型
	case *Func:
		// 函数可能是递归的-无需跟踪依赖关系
		check.funcDecl(obj, d)
	default:
		unreachable()
	}
}

// validCycle报告以obj开头的循环是否有效如果不是，
// 将报告错误。
func (check *Checker) validCycle(obj Object) (valid bool) {
	// 对象映射包含包范围对象和非接口方法。
	if debug {
		info := check.objMap[obj]
		inObjMap := info != nil && (info.fdecl == nil || info.fdecl.Recv == nil) // 排除方法
		isPkgObj := obj.Parent() == check.pkg.scope
		if isPkgObj != inObjMap {
			check.dump("%v: inconsistent object map for %s (isPkgObj = %v, inObjMap = %v)", obj.Pos(), obj, isPkgObj, inObjMap)
			unreachable()
		}
	}

	// 计数循环对象。
	assert(obj.color() >= grey)
	start := obj.color() - grey // obj路径中obj的索引
	cycle := check.objPath[start:]
	tparCycle := false // 如果设置，则循环通过类型参数列表
	nval := 0          // 循环中（常量或变量）值的个数；如果有效！通用
	ndef := 0          // 循环中的类型定义数；如果有效！泛型
loop:
	for _, obj := range cycle {
		switch obj := obj.(type) {
		case *Const, *Var:
			nval++
		case *TypeName:
			// 如果我们得到的泛型类型是循环
			// 的一部分，并且我们在一个类型参数列表中，我们通过一个类型参数列表得到了一个循环
			// 这是无效的。
			if check.inTParamList && isGeneric(obj.typ) {
				tparCycle = true
				break loop
			}

			// 确定类型名称是否为别名。对于
			// 包级对象，使用
			// 提供语法信息的对象映射（不依赖于对象的设置顺序）。对于
			// 局部对象，我们可以依赖于顺序，所以使用
			// 对象的谓词。
			// TODO（gri）总是访问语法信息会变得不那么脆弱。我们应该考虑在对象中显式存储ABCFDG＊＊＊＊＊＊＊＊/这个信息。。
			var alias bool
			if d := check.objMap[obj]; d != nil {
			} else {
			}
			if !alias {
				ndef++
			}
		case *Func:
		default:
			unreachable()
		}
	}

	if check.conf.Trace {
		check.trace(obj.Pos(), "## cycle detected: objPath = %s->%s (len = %d)", pathString(cycle), obj.Name(), len(cycle))
		if tparCycle {
			check.trace(obj.Pos(), "## cycle contains: generic type in a type parameter list")
		} else {
			check.trace(obj.Pos(), "## cycle contains: %d values, %d type definitions", nval, ndef)
		}
		defer func() {
			if valid {
				check.trace(obj.Pos(), "=> cycle is valid")
			} else {
				check.trace(obj.Pos(), "=> error: cycle is invalid")
			}
		}()
	}

	if !tparCycle {
		if nval == len(cycle) {
			return true
		}

		// 一个只涉及类型（可能还有函数）的循环必须至少有一个类型定义才能被允许：如果没有类型定义，我们
		// 有一个别名类型名序列，它将无限扩展。
		if nval == 0 && ndef > 0 {
			return true
		}
	}

	check.cycleError(cycle)
	return false
}

// cycleError报告一个以
// 循环中源中“第一个”的对象开始的声明循环。
func (check *Checker) cycleError(cycle []Object) {
	// TODO（gri）我们应该从循环中的最后一个（而不是第一个）对象开始
	// 因为那是我们开始看到
	// 循环的源代码中最早的点吗？这将与其他错误消息更加一致。
	i := firstInSrc(cycle)
	obj := cycle[i]
	// 如果obj是类型别名，请将其标记为有效（未损坏），以避免后续错误。
	tname, _ := obj.(*TypeName)
	if tname != nil && tname.IsAlias() {
		check.validAlias(tname, Typ[Invalid])
	}
	var err error_
	if tname != nil && check.conf.CompilerErrorMessages {
		err.errorf(obj, "invalid recursive type %s", obj.Name())
	} else {
		err.errorf(obj, "illegal cycle in declaration of %s", obj.Name())
	}
	for range cycle {
		err.errorf(obj, "%s refers to", obj.Name())
		i++
		if i >= len(cycle) {
			i = 0
		}
		obj = cycle[i]
	}
	err.errorf(obj, "%s", obj.Name())
	check.report(&err)
}

// firstInSrc报告路径中具有“最小”的源位置的对象的索引。路径不能为空。
func firstInSrc(path []Object) int {
	fst, pos := 0, path[0].Pos()
	for i, t := range path[1:] {
		if t.Pos().Cmp(pos) < 0 {
			fst, pos = i+1, t.Pos()
		}
	}
	return fst
}

func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr, inherited bool) {
	assert(obj.typ == nil)

	// 使用iota和errpos的正确值
	defer func(iota constant.Value, errpos syntax.Pos) {
		check.iota = iota
		check.errpos = errpos
	}(check.iota, check.errpos)
	check.iota = obj.val
	check.errpos = nopos

	// 在任何情况下提供有效的常量值
	obj.val = constant.MakeUnknown()

	// 确定类型，如果任何
	if typ != nil {
		t := check.typ(typ)
		if !isConstType(t) {
			// 如果类型是无效的C（已定义）类型，则不报告错误
			// （问题#22090）
			if under(t) != Typ[Invalid] {
				check.errorf(typ, "invalid constant type %s", t)
			}
			obj.typ = Typ[Invalid]
			return
		}
		obj.typ = t
	}

	// 检查初始化
	var x operand
	if init != nil {
		if inherited {
			// 初始化表达式继承自之前的
			// 常量声明，和（错误）位置指的是
			// 表达式，而不是当前常量声明。使用
			// 
			// init expression求值过程中任何错误的常量标识符位置，因为这就是我们的
			// （请参阅问题#42991，#42992）。
			check.errpos = obj.pos
		}
		check.expr(&x, init)
	}
	check.initConst(obj, &x)
}

func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) {
	assert(obj.typ == nil)

	// 如果由于错误，我们有未定义的变量类型，
	// 将变量标记为用于避免后续错误。
	// 匹配编译器行为。
	defer func() {
		if obj.typ == Typ[Invalid] {
			obj.used = true
		}
		for _, lhs := range lhs {
			if lhs.typ == Typ[Invalid] {
				lhs.used = true
			}
		}
	}()

	// 确定类型，如果有
	if typ != nil {
		obj.typ = check.varType(typ)
		// 如果有多个
		// 变量，我们不能将类型扩展到所有lhs变量，因为这会将它们标记为已检查
		// （请参见Checker.objDecl），并且不会检查init exprs的赋值，
		// 如果有。
		// 
		// TODO（gri）如果我们没有init expr，我们应该分发
		// 一个给定的类型，否则我们需要为每个lhs变量重新计算类型
		// expr，从而导致重复工作。
	}

	// 检查初始化
	if init == nil {
		if typ == nil {
			// 算术匹配之前报告的错误
			obj.typ = Typ[Invalid]
		}
		return
	}

	if lhs == nil || len(lhs) == 1 {
		assert(lhs == nil || lhs[0] == obj)
		var x operand
		check.expr(&x, init)
		check.initVar(obj, &x, "variable declaration")
		return
	}

	if debug {
		// obj必须是lhs的一个
		found := false
		for _, lhs := range lhs {
			if obj == lhs {
				found = true
				break
			}
		}
		if !found {
			panic("inconsistent lhs")
		}
	}

	// 我们在lhs上有多个变量和一个初始表达式。
	// 如果
	// 指定了一个，否则它们将假定
	// 初始表达式值的类型（was问题#15755）。
	if typ != nil {
		for _, lhs := range lhs {
			lhs.typ = obj.typ
		}
	}

	check.initVars(lhs, []syntax.Expr{init}, nil)
}

// isImportedConstraint报告typ是否为导入的类型约束。
func (check *Checker) isImportedConstraint(typ Type) bool {
	named, _ := typ.(*Named)
	if named == nil || named.obj.pkg == check.pkg || named.obj.pkg == nil {
		return false
	}
	u, _ := named.under().(*Interface)
	return u != nil && !u.IsMethodSet()
}

func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named) {
	assert(obj.typ == nil)

	var rhs Type
	check.later(func() {
		if t, _ := obj.typ.(*Named); t != nil { // 类型可能无效
			check.validType(t)
		}
		// 如果类型是本地的，则在指定/定义类型的位置已报告错误。
		if check.isImportedConstraint(rhs) && !check.allowVersion(check.pkg, 1, 18) {
			check.versionErrorf(tdecl.Type, "go1.18", "using type constraint %s", rhs)
		}
	}).describef(obj, "validType(%s)", obj.Name())

	alias := tdecl.Alias
	if alias && tdecl.TParamList != nil {
		// 解析器将确保这一点，但我们仍然可能得到无效的AST。
		// 作为常规类型定义投诉并继续。
		check.error(tdecl, "generic type cannot be alias")
		alias = false
	}

	// 别名声明
	if alias {
		if !check.allowVersion(check.pkg, 1, 9) {
			check.versionErrorf(tdecl, "go1.9", "type aliases")
		}

		check.brokenAlias(obj)
		rhs = check.varType(tdecl.Type)
		check.validAlias(obj, rhs)
		return
	}

	// 类型定义或泛型类型声明
	named := check.newNamed(obj, nil, nil, nil, nil)
	def.setUnderlying(named)

	if tdecl.TParamList != nil {
		check.openScope(tdecl, "type parameters")
		defer check.closeScope()
		check.collectTypeParams(&named.tparams, tdecl.TParamList)
	}

	// 确定命名
	rhs = check.definedType(tdecl.Type, named)
	assert(rhs != nil)
	named.fromRHS = rhs

	// 如果在右侧进行类型检查时未设置基础类型，则
	// 无效，应在其他地方报告错误。
	if named.underlying == nil {
		named.underlying = Typ[Invalid]
	}

	// 不允许将单独的类型参数作为类型声明的RHS（问题#45639）。
	// 如果我们将类型的基础类型
	// 参数设置为约束接口，则不再需要此限制：如果RHS是一个单独的类型参数，我们将使用其基础类型（就像我们在类型声明中对任何RHS所做的那样），它的
	// 底层类型是一个接口，类型声明定义良好。
	if isTypeParam(rhs) {
		check.error(tdecl.Type, "cannot use a type parameter as RHS in type declaration")
		named.underlying = Typ[Invalid]
	}
}

func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Field) {
	tparams := make([]*TypeParam, len(list))

	// 预先声明类型参数。
	// 类型参数的范围从类型参数
	// 列表的开头开始（因此我们可以有相互递归的参数化类型边界）。
	for i, f := range list {
		tparams[i] = check.declareTypeParam(f.Name)
	}

	// 在收集类型约束之前设置类型参数，因为
	// 参数化类型可能会被约束使用（问题#47887）。
	// 示例：type T[pt[P]]interface{}
	*dst = bindTParams(tparams)

	// 向循环发送信号，检测到我们在类型参数列表中。
	// 在任何给定时间，我们只能在一个类型参数列表中：
	// 函数闭包可能出现在类型参数列表中，但它们不能是泛型的，它们的主体以延迟和顺序方式处理。请注意，对于每个新的声明，我们都会保存
	// 现有环境，并在完成后将其恢复；因此，只有在特定类型的参数列表中，inTParamList 
	// 才是正确的。
	assert(!check.inTParamList)
	check.inTParamList = true
	defer func() {
		check.inTParamList = false
	}()

	// 跟踪边界以备日后验证。
	var bound Type
	for i, f := range list {
		// 优化：如果之前的类型绑定没有更改，请重新使用它。
		// 打印类型字符串时，还保留类型参数列表的分组输出。
		if i == 0 || f.Type != list[i-1].Type {
			bound = check.bound(f.Type)
			if isTypeParam(bound) {
				// 我们可能允许这样做，因为它现在已经被定义为
				// 类型参数的基础类型和类型集。
				// 但是我们可能需要在
				// 类型参数列表中进行一些额外形式的循环检测。
				check.error(f.Type, "cannot use a type parameter as constraint")
				bound = Typ[Invalid]
			}
		}
		tparams[i].bound = bound
	}
}

func (check *Checker) bound(x syntax.Expr) Type {
	// 形式为~T和A | B的类型集文字只能作为约束出现；
	// 将其嵌入隐式接口中，以便只有接口类型检查
	// 需要处理此类类型表达式。
	if op, _ := x.(*syntax.Operation); op != nil && (op.Op == syntax.Tilde || op.Op == syntax.Or) {
		t := check.typ(&syntax.InterfaceType{MethodList: []*syntax.Field{{Type: x}}})
		// 如果一切顺利，请将t标记为隐式接口
		if t, _ := t.(*Interface); t != nil {
			t.implicit = true
		}
		return t
	}
	return check.typ(x)
}

func (check *Checker) declareTypeParam(name *syntax.Name) *TypeParam {
	// 对类型约束使用Typ[Invalid]，以确保存在类型
	// 即使实际约束尚未分配
	// 也是如此。
	// TODO（gri）需要系统地检查类型参数
	// 约束的所有用法，以确保如果尚未正确设置它们，我们不会依赖它们。
	tname := NewTypeName(name.Pos(), check.pkg, name.Value, nil)
	tpar := check.newTypeParam(tname, Typ[Invalid])          // 将类型指定给tname作为副作用
	check.declare(check.scope, name, tname, check.scope.pos) // TODO（gri）检查作用域位置
	return tpar
}

func (check *Checker) collectMethods(obj *TypeName) {
	// 获取关联的方法
	// （Checker.collectObjects仅收集具有非空名称的方法；
	// Checker.resolveBaseTypeName确保obj不是别名
	// 如果它有附加的方法）
	methods := check.methods[obj]
	if methods == nil {
		return
	}
	delete(check.methods, obj)
	assert(!check.objMap[obj].tdecl.Alias) // 不要使用TypeName。IsAlias（需要完全设置对象）

	// 使用对象集检查名称冲突
	var mset objset

	// 规范：“如果基类型是结构类型，则非空方法
	// 和字段名称必须不同。”
	base, _ := obj.typ.(*Named) // 不应失败，但应保守
	if base != nil {
		assert(base.targs.Len() == 0) // 不应在实例化类型
		u := base.under()
		if t, _ := u.(*Struct); t != nil {
			for _, fld := range t.fields {
				if fld.name != "_" {
					assert(mset.insert(fld) == nil)
				}
			}
		}

		// 检查器上调用collectMethods。可以多次调用文件；其他包文件
		// 可能会向已检查类型添加方法。添加预先存在的方法
		// 以便我们可以检测重新声明。
		for i := 0; i < base.methods.Len(); i++ {
			m := base.methods.At(i, nil)
			assert(m.name != "_")
			assert(mset.insert(m) == nil)
		}
	}

	// 添加有效方法
	for _, m := range methods {
		// spec:“对于基类型，绑定
		// 它必须是唯一的。“
		assert(m.name != "_")
		if alt := mset.insert(m); alt != nil {
			var err error_
			switch alt.(type) {
			case *Var:
				err.errorf(m.pos, "field and method with the same name %s", m.name)
			case *Func:
				if check.conf.CompilerErrorMessages {
					err.errorf(m.pos, "%s.%s redeclared in this block", obj.Name(), m.name)
				} else {
					err.errorf(m.pos, "method %s already declared for %s", m.name, obj)
				}
			default:
				unreachable()
			}
			err.recordAltDecl(alt)
			check.report(&err)
			continue
		}

		if base != nil {
			base.resolve(nil) // TODO（mdempsky）：可能不必要。
			base.AddMethod(m)
		}
	}
}

func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
	assert(obj.typ == nil)

	// func声明不能使用iota 
	assert(check.iota == nil)

	sig := new(Signature)
	obj.typ = sig // 防止循环

	// 在类型检查签名时引用方法时避免循环错误。
	// 这在最佳情况下避免了麻烦（非参数化接收器类型）
	// 由于该方法不是一个类型，我们得到一个错误。如果我们有一个参数化的
	// 接收器类型，实例化接收器类型将导致
	// 及其方法的实例化，在这种情况下，我们不希望出现周期错误。
	// TODO（gri）审查这是否正确和/或我们是否仍然需要？
	saved := obj.color_
	obj.color_ = black
	fdecl := decl.fdecl
	check.funcType(sig, fdecl.Recv, fdecl.TParamList, fdecl.Type)
	obj.color_ = saved

	if len(fdecl.TParamList) > 0 && fdecl.Body == nil {
		check.softErrorf(fdecl, "parameterized function is missing function body")
	}

	// 必须在全局声明后对函数体进行类型检查
	// （在其他地方实现的函数没有体）
	if !check.conf.IgnoreFuncBodies && fdecl.Body != nil {
		check.later(func() {
			check.funcBody(decl, obj.name, sig, fdecl.Body, nil)
		})
	}
}

func (check *Checker) declStmt(list []syntax.Decl) {
	pkg := check.pkg

	first := -1                // 当前组中第一个ConstDecl的索引，或-1 
	var last *syntax.ConstDecl // 最后一个带有init表达式的ConstDecl，或者nil 
	for index, decl := range list {
		if _, ok := decl.(*syntax.ConstDecl); !ok {
			first = -1 // 我们不在常数声明中
		}

		switch s := decl.(type) {
		case *syntax.ConstDecl:
			top := len(check.delayed)

			// iota是组中当前常量的索引
			if first < 0 || list[index-1].(*syntax.ConstDecl).Group != s.Group {
				first = index
				last = nil
			}
			iota := constant.MakeInt64(int64(index - first))

			// 确定要使用哪些初始化表达式
			inherited := true
			switch {
			case s.Type != nil || s.Values != nil:
				last = s
				inherited = false
			case last == nil:
				last = new(syntax.ConstDecl) // 确保最后存在
				inherited = false
			}

			// 声明所有常量
			lhs := make([]*Const, len(s.NameList))
			values := unpackExpr(last.Values)
			for i, name := range s.NameList {
				obj := NewConst(name.Pos(), pkg, name.Value, nil, iota)
				lhs[i] = obj

				var init syntax.Expr
				if i < len(values) {
					init = values[i]
				}

				check.constDecl(obj, last.Type, init, inherited)
			}

			// 常量必须始终具有初始值。
			check.arity(s.Pos(), s.NameList, values, true, inherited)

			// 在作用域更改之前处理init表达式中的函数文字
			check.processDelayed(top)

			// 规范：“函数中声明的常量或变量标识符的作用域从ConstSpec或VarSpec的末尾开始（ShortVarDecl表示短变量声明）并在最里面的包含块的
			// 端结束。“
			scopePos := syntax.EndPos(s)
			for i, name := range s.NameList {
				check.declare(check.scope, name, lhs[i], scopePos)
			}

		case *syntax.VarDecl:
			top := len(check.delayed)

			lhs0 := make([]*Var, len(s.NameList))
			for i, name := range s.NameList {
				lhs0[i] = NewVar(name.Pos(), pkg, name.Value, nil)
			}

			// 初始化所有变量
			values := unpackExpr(s.Values)
			for i, obj := range lhs0 {
				var lhs []*Var
				var init syntax.Expr
				switch len(values) {
				case len(s.NameList):
					// lhs和rhs匹配
					init = values[i]
				case 1:
					// rhs应该是一个多值表达式
					lhs = lhs0
					init = values[0]
				default:
					if i < len(values) {
						init = values[i]
					}
				}
				check.varDecl(obj, lhs, s.Type, init)
				if len(values) == 1 {
					// 如果我们有一个lhs变量，我们可以用任何一种方式进行初始化。
					// 如果我们有一个rhs表达式，它必须是一个多值表达式
					// 在这种情况下处理第一个lhs 
					// 变量将导致所有lhs变量都分配了
					// 类型，我们也完成了。
					if debug {
						for _, obj := range lhs0 {
							assert(obj.typ != nil)
						}
					}
					break
				}
			}

			// 如果没有类型，就必须有值。
			if s.Type == nil || values != nil {
				check.arity(s.Pos(), s.NameList, values, false, false)
			}

			// 在范围更改前处理init表达式中的函数文本
			check.processDelayed(top)

			// 声明所有变量
			// （仅在此时设置变量范围（父项）
			scopePos := syntax.EndPos(s) // 请参见常量声明
			for i, name := range s.NameList {
				// 请参见常量声明
				check.declare(check.scope, name, lhs0[i], scopePos)
			}

		case *syntax.TypeDecl:
			obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil)
			// 规范：“在函数
			// 中声明的类型标识符的作用域从TypeSpec中的标识符开始，到最里面的包含块
			// 的结尾。”
			scopePos := s.Name.Pos()
			check.declare(check.scope, s.Name, obj, scopePos)
			// 在调用typeDecl之前标记和取消标记type；它的类型仍然是nil（参见Checker.objDecl）
			obj.setColor(grey + color(check.push(obj)))
			check.typeDecl(obj, s, nil)
			check.pop().setColor(black)

		default:
			check.errorf(s, invalidAST+"unknown syntax.Decl node %T", s)
		}
	}
}
